package com.cskaoyan.javase.recursion._0introduction;

/**
 * 递归的引入
 * 递归的定义
 * 我们已经学习过方法，使用过方法了。
 * 方法体中是可以调用方法的，那么如果在方法体中调用方法自身呢？
 *
 * 特别的，在一个方法当中再次调用这个方法，就像故事里提到同样的故事一样
 * 我们把方法在运行时调用自身的情况，称之为递归，又叫做递归调用。
 *
 * 使用递归的注意事项:
 * 1.要想递归,最起码的,需要在方法体中自身调用自身方法
 * 把方法中该条语句,称之为"递归体"
 * 要想 使用递归,递归体是不可获取的,是必须的
 *
 * 2.要想递归能够正常执行,而不是栈溢出,就必须给递归一个终止的条件,使得方法能够调用结束出栈
 * 这称之为"递归的出口"
 * 一个正常合法的递归,必须要有递归的出口
 *
 * 递归体和递归的出口称之为"递归两要素" 合法正常的递归,必须要有这两个结构.
 *
 * 3.递归有递归体有递归出口以后,就一定能够正常运行吗?
 * 不一定,如果递归的出口过于遥远,导致递归的次数仍然超出了栈内存的大小
 * 仍然会导致栈溢出
 * 所以递归仍然需要考虑递归的次数和栈内存的大小关系,称之为"递归的深度"
 *
 * 总之,递归的使用是很危险的,稍有不慎就会导致栈溢出错误,所以在实际开发中
 * 能不用递归就不用递归,实在迫不得已了再去考虑用递归.
 *
 * @since 11:12
 * @author wuguidong@cskaoyan.onaliyun.com
 */
public class Demo {
    public static void main(String[] args) {
        /*
            修改新增递归体以后,结果是55
         */
        System.out.println(sum(15000));
        /*
            分析以上方法的执行结果:
            sum(10) = 10 + sum(9);
            sum(9) = 9 + sum(8);
            sum(8) = 8 + sum(7);
            ...
            以上的过程是不可能停止的
            思考结果是以下:
            1.死循环
            2.程序报错
            3.电脑炸了

           实际上,以上代码一旦运行,程序会报错,抛出异常
           StackOverflowError(栈溢出错误)
           Error也属于是异常的一种,但是它远比Exception要严重,是程序的严重错误

           思考:
           溢出指的是内存不够用了,称之为溢出.
                栈溢出是什么栈溢出了? 是JVM栈溢出了 不是本地方法栈
                为什么会栈溢出? 因为方法一直被调用,没有调用结束
                    所以就不停有方法栈帧进栈,却没有方法栈帧出栈
                    只进不出,终究会导致栈内存不够用,产生栈溢出
                    Method 'sum()' recurses infinitely, and can only end by throwing an exception
         */
    }

    // 递归方法,num必须输入一个大于0的数
    public static long sum(int num) {
        // 递归的出口就是触发一个条件,不再去调用自身方法
        if (num == 1) {
            return 1;
        }
        return num + sum(num - 1);
    }

}
